#pragma once
#include "../Common/Net.hpp"
#include "../Common/Detail.hpp"
#include "../Common/Detail.hpp"
#include "../Common/Message.hpp"
#include <set>

namespace zgwrpc
{
    namespace server
    {
        // 服务提供者的管理
        class ProviderManager
        {
        public:
            using ptr = shared_ptr<ProviderManager>;
            struct Provider
            {
                using ptr = shared_ptr<Provider>;
                std::mutex _mutex;

                Address host;                     // 主机地址
                std::vector<std::string> methods; // 提供的服务名称,
                BaseConnection::ptr conn;         // 对应连接

                Provider(const BaseConnection::ptr &c, const Address &h) : conn(c), host(h) {}
                void AppendMethod(const std::string &method)
                {
                    unique_lock<std::mutex> lock(_mutex);
                    methods.emplace_back(method);
                }
            };

            Address MethodHosts(const std::string &method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                Address result;
                auto it = _providers.find(method);
                if(it!= _providers.end())
                {
                    for(auto &provider : it->second)
                    {
                        result=provider->host;
                    }
                }
                return result;
            }
            // 当一个服务注册时进行调用，添加对应的信息
            
            void AddProvider(const BaseConnection::ptr &c, const Address &h, const std::string &method)
            {
                Provider::ptr provider;
                // 首先去_connections中查找是否有provider，如果有，则不需要创建信的连接映射
                {
                    std::lock_guard<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it != _conns.end())
                    {
                        provider = it->second;
                    }
                    else
                    {
                        provider = make_shared<Provider>(c, h);
                        _conns.insert(std::make_pair(c, provider));
                    }
                    // 2.查看当前是否有对应方法，如果没有则创建新的方法，和服务映射
                    auto &providers = _providers[method];
                    providers.insert(provider);
                }
                // 3.在provider当中添加自己的方法
                provider->AppendMethod(method);
            }
            // 当一个服务注销时进行调用，删除对应的信息
            void DeleteProvider(const BaseConnection::ptr &c)
            {
                // 查找是否有对应的provider
                LOG(LogLevel::DEBUG) << "服务提供者下线";
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it == _conns.end())
                    {
                        LOG(LogLevel::ERROR) << "没有找到对应的provider";
                        return; // 如果不存在这个provider就说明根本没有这个连接建立
                    }
                    for (auto &method : it->second->methods)
                    {
                        auto &providers = _providers[method];
                        providers.erase(it->second);
                    }
                    _conns.erase(it);
                }
            }

            Provider::ptr GetProvider(BaseConnection::ptr c)
            {
                unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it != _conns.end())
                {
                    return it->second;
                }
                return nullptr;
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, std::set<Provider::ptr>> _providers; // 能提供对应方法与对应的provider进行映射
            std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;       // 连接与Provider的映射
        };

        class DiscovererManager
        {
        public:
            using ptr = shared_ptr<DiscovererManager>;
            struct Discoverer
            {
                using ptr = shared_ptr<Discoverer>;
                BaseConnection::ptr conn;         // 发现者关联的客户端连接
                std::vector<std::string> methods; // 发现的服务名称
                Discoverer(const BaseConnection::ptr &c) : conn(c) {}
                void AppendMethod(const std::string &method)
                {
                    methods.emplace_back(method);
                }
            };
            // 当一个客户端连接时，添加对应的发现者信息
            Discoverer::ptr AddDiscoverer(const BaseConnection::ptr &c, const std::string &method)
            {
                Discoverer::ptr discover;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(c);
                    if (it != _conns.end())
                    {
                        discover = it->second;
                    }
                    else
                    {
                        discover = make_shared<Discoverer>(c);
                        _conns.insert(make_pair(c, discover));
                    }
                    auto &discoverers = _discoverers[method];
                    discoverers.insert(discover);
                }
                discover->AppendMethod(method);
                return discover;
            }

            // 当一个客户端断开连接时，删除对应的发现者信息
            void DeleteDiscoverer(const BaseConnection::ptr &c)
            {
                LOG(LogLevel::DEBUG) << "服务发现者下线";
                unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it == _conns.end())
                {
                    // 不是一个服务发现者
                    return;
                }
                for (auto &method : it->second->methods)
                {
                    auto &discover = _discoverers[method];
                    discover.erase(it->second);
                }
                _conns.erase(it);
            }

            // 当一个服务上线时，通知所有注册了该服务的客户端
            void OnlineNotify(const string &method, const Address &host)
            {
                return OnOffSend(method, host, ServiceOpType::SERVICE_ONLINE);
            }
            // 当一个服务下线时，通知所有注册了该服务的客户端
            void OfflineNotify(const string &method, const Address &host)
            {
                return OnOffSend(method, host, ServiceOpType::SERVICE_OFFLINE);
            }
            // 当一个客户端连接时，添加对应的服务提供者信息

        private:
            void OnOffSend(const std::string &method, const Address &host, const ServiceOpType &op_type)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _discoverers.find(method);
                if (it == _discoverers.end())
                {
                    return;
                }
                auto msg = MessageFactory::createMessage(MType::RSP_SERVICE);
                auto msg_req = dynamic_pointer_cast<ServiceResponse>(msg);
                msg_req->setId(Uuid::Getid());
                msg_req->setMType(MType::REQ_SERVICE);
                msg_req->setMethod(method);
                msg_req->setHost(host);
                msg_req->setServiceOpType(ServiceOpType::SERVICE_ONLINE);
                for (auto &discover : it->second)
                {
                    discover->conn->send(msg);
                }
            }
            std::mutex _mutex;
            std::unordered_map<BaseConnection::ptr, Discoverer::ptr> _conns;
            std::unordered_map<std::string, std::set<Discoverer::ptr>> _discoverers; // 那些服务被哪些客户发现过，方便服务下线通知等操作
        };

        class PDManger
        {
        public:
            PDManger() : _provider_manager(make_shared<ProviderManager>()), _discoverer_manager(make_shared<DiscovererManager>())
            {
            }
            using ptr = shared_ptr<PDManger>;

            void OnServiceRequest(const BaseConnection::ptr &c, const ServiceRequest::ptr &req)
            {
                // 服务注册
                LOG(LogLevel::DEBUG) << "收到服务请求";
                ServiceOpType op_type = req->serviceOpType();
                LOG(LogLevel::DEBUG) << "服务操作类型：";
                std::string method = req->method();
                cout << "method:" << method << endl;
                if (op_type == ServiceOpType::SERVICE_REGISTER)
                {
                    // 新增服务者

                    _provider_manager->AddProvider(c, req->host(), req->method());
                    LOG(LogLevel::DEBUG) << "新增服务者";
                    // 进行服务上线通知
                    _discoverer_manager->OnlineNotify(req->method(), req->host());
                    LOG(LogLevel::DEBUG) << "进行服务上线通知";
                    return registryResponse(c, req);
                }
                // 服务发现
                else if (op_type == ServiceOpType::SERVICE_DISCOVERY)
                {
                    // 新增服务发现者
                    _discoverer_manager->AddDiscoverer(c, req->method());
                    return discoveryResponse(c, req);
                }
                else
                {
                    LOG(LogLevel::ERROR) << "服务操作类型错误";
                }
            }

            void OnServiceShutdown(const BaseConnection::ptr &c)
            {
                auto provider = _provider_manager->GetProvider(c);
                if (provider.get() != nullptr) // 如果是服务提供者
                {
                    for (auto &method : provider->methods)
                    {
                        // 进行服务下线通知
                        _discoverer_manager->OfflineNotify(method, provider->host);
                    }
                    _provider_manager->DeleteProvider(c);
                }
                // 如果是服务发现者
                _discoverer_manager->DeleteDiscoverer(c);
            }

        private:
            void discoveryResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
            {
                auto msg_rsp = MessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->rid());
                cout << "msg_rsp->id():" << msg_rsp->rid() << endl;
                msg_rsp->setMType(MType::RSP_SERVICE);
                msg_rsp->setServiceOpType(ServiceOpType::SERVICE_DISCOVERY);
                auto hosts = _provider_manager->MethodHosts(msg->method());
                if (hosts.first.empty() || hosts.second == 0)
                {
                    msg_rsp->setRCode(RCode::RCODE_NOT_FOUND_SERVICE);
                    return conn->send(msg_rsp);
                }
                msg_rsp->setRCode(RCode::RCODE_OK);
                msg_rsp->setMethod(msg->method());
                msg_rsp->setHost(hosts);
                return conn->send(msg_rsp);
            }
            void registryResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
            {
                auto msg_rsp = MessageFactory::create<ServiceResponse>();
                msg_rsp->setId(msg->rid());
                cout << "msg_rsp->id():" << msg_rsp->rid() << endl;
                msg_rsp->setMType(MType::RSP_SERVICE);
                msg_rsp->setRCode(RCode::RCODE_OK);
                msg_rsp->setServiceOpType(ServiceOpType::SERVICE_REGISTER);
                conn->send(msg_rsp);
            }

            ProviderManager::ptr _provider_manager;
            DiscovererManager::ptr _discoverer_manager;
        };

    }
}
